package jp.co.kayo.gae.takidashibot.utils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.google.appengine.api.urlfetch.HTTPResponse;
import com.google.appengine.api.urlfetch.URLFetchService;
import com.google.appengine.api.urlfetch.URLFetchServiceFactory;
import com.google.appengine.repackaged.org.json.JSONArray;
import com.google.appengine.repackaged.org.json.JSONObject;

public class Utils {
    private static final boolean debug = true;
    private static final Logger log = Logger.getLogger(Utils.class.getName());

    static final String BITLYAPISHORTEN = "http://api.bit.ly/v3/shorten?apiKey=";
    static final String BITLYAPIEXPAND = "http://api.bit.ly/v3/expand?apiKey=";
    static final String BITLYLOGIN = "&login=";
    static final String BITLYLONGURL = "&longUrl=";
    static final String BITLYHASH = "&hash=";
    static final String BITLYSHORTURL = "&shortUrl=";
    static final String BITLYFORMAT = "&format=txt";
    static final String BITLYURL = "http://bit.ly/";
    
    public static double getDouble(Object s){
        if(s!=null){
            try{
                return Double.parseDouble(s.toString());
            }
            catch(Exception e){}
        }
        return 0;
    }
    
    public static int getInt(Object s){
        if(s!=null ){
            try{
                return Integer.parseInt(s.toString());
            }
            catch(Exception e){}
        }
        return 0;
    }

    public static String fixString(Object o){
        if(o == null){
            return "";
        }
        else{
            return o.toString();
        }
    }
    
    public static String urlShorter(String s){
        try {
            String targetURL = BITLYAPISHORTEN + "R_b73da8bcaa024e308246dd17b270d23a" +
            BITLYLOGIN + "yokmama" + 
            BITLYFORMAT+ BITLYLONGURL + 
            URLEncoder.encode(s,"UTF-8");
            
            URL url = new URL(targetURL);
            HttpURLConnection urlconn = 
                                (HttpURLConnection)url.openConnection();
            urlconn.setRequestMethod("GET");
            urlconn.setInstanceFollowRedirects(false);
            urlconn.setRequestProperty("Connection", "close");
            urlconn.connect();

            if(urlconn.getResponseCode() ==200){
                BufferedReader bin;
                bin = new BufferedReader(new InputStreamReader(
                                                    urlconn.getInputStream()));
                String line;
                if(( line = bin.readLine()) != null){
                    return line;
                }
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        return "";
    }
    
    public static String getResponse(String s, String enc) throws Exception{
        URL url = new URL(s);
        BufferedReader in = null;
        try{
            // 接続します
            URLFetchService service = URLFetchServiceFactory.getURLFetchService();
            
            HTTPResponse res = service.fetch(url);
            if(res.getResponseCode() == 200){
                if(enc!=null){
                    return new String(res.getContent(), enc);
                }
                else{
                    return new String(res.getContent());
                }
            }
        }
        finally{
            if(in!=null){
                try{
                    in.close();
                }
                catch(Exception e){}
            }
        }
        return null;
    }
    
    /***
     * GEO Code取得
     * @param addr
     * @return
     */
    public static double[] getGeoCode(String addr){
        double[] ret = getGeoCodeYahoo(addr);
        if(ret!=null && ret.length>0){
            return ret;
        }
        else{
            return getGeoCodeGoogle(addr);
        }
    }
    
    public static double[] getGeoCodeYahoo(String addr){
        //http://geo.search.olp.yahooapis.jp/OpenLocalPlatform/V1/geoCoder?appid=<あなたのアプリケーションID&query=%e6%9d%b1%e4%ba%ac%e9%83%bd%e6%b8%af%e5%8c%ba%e5%85%ad%e6%9c%ac%e6%9c%a8
        try {
            StringBuilder url = new StringBuilder();
            url.append("http://geo.search.olp.yahooapis.jp/OpenLocalPlatform/V1/geoCoder?");
            url.append("appid=").append(Consts.YAHOO_ID);
            url.append("&output=json");
            url.append("&query=").append(URLEncoder.encode(addr, "UTF-8"));
            
            String json = getResponse(url.toString(), null);
            
            JSONObject jsonobj = new JSONObject(json);
            JSONArray features = jsonobj.getJSONArray("Feature");
            if(features!=null && features.length()>0){
                JSONObject feature = features.getJSONObject(0);
                JSONObject geometry = feature.getJSONObject("Geometry");
                if(geometry!=null){
                    String ret =  geometry.getString("Coordinates");
                    if(ret!=null){
                        String[] sret = ret.split(",");
                        if(sret!=null && sret.length>1){
                            double lng = getDouble(sret[0]);
                            double lat = getDouble(sret[1]);
                            if(lat!=-1 && lng !=-1){
                                return new double[]{lat, lng};
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.log(Level.WARNING, "getAddressByYahoo", e);
        }
        return null;
    }
    
    public static double[] getGeoCodeGoogle(String addr){
        BufferedReader in = null;
        try{
            StringBuilder str = new StringBuilder();
            str.append("http://maps.google.com/maps/api/geocode/json?address=");
            str.append(URLEncoder.encode(addr, "UTF-8"));
            str.append("&sensor=false");
            
            // URLクラスのインスタンスを生成
            URL url = new URL(str.toString());
            
            // 接続します
            URLConnection con = url.openConnection();
            con.setRequestProperty("Referer", "http://takidasibot.appspot.com/takidasibot");

            // 入力ストリームを取得
            in = new BufferedReader(
                  new InputStreamReader(
                  con.getInputStream(),"UTF-8"));
    
            // 一行ずつ読み込みます
            StringBuffer json= new StringBuffer();
            String line = null;
            while ((line = in.readLine()) != null) {
              // 表示します
                json.append(line);
            }
            log.log(Level.INFO, "str="+str.toString());
            log.log(Level.INFO, "json="+json.toString());
            JSONObject jsonobj = new JSONObject(json.toString());
            JSONArray result = jsonobj.getJSONArray("results");
            if(result!=null && result.length()>0){
                jsonobj = result.getJSONObject(0);
                JSONObject geometry = jsonobj.getJSONObject("geometry");
                if(geometry!=null){
                    JSONObject location = geometry.getJSONObject("location");
                    if(location !=null){
                        double lat = location.getDouble("lat");
                        double lng = location.getDouble("lng");
                        return new double[]{lat, lng};
                    }
                }
            }
            //取得できなかったので他の方法で取得を試みる
            //http://www.geocoding.jp/api/?q=山形県山形市+上桜田+3-4-3
            if(in!=null){
                in.close();
            }
            
            url = new URL("http://www.geocoding.jp/api/?q="+URLEncoder.encode(addr, "UTF-8"));
            // 接続します
            con = url.openConnection();
            con.setRequestProperty("Referer", "http://maps.google.com/");

            // 入力ストリームを取得
            in = new BufferedReader(
                  new InputStreamReader(
                  con.getInputStream(),"UTF-8"));
    
            // 一行ずつ読み込みます
            json= new StringBuffer();
            line = null;
            while ((line = in.readLine()) != null) {
              // 表示します
                json.append(line);
            }
            String xml = json.toString();
            //<lat>38.217562</lat>
            //<lng>140.344422</lng>
            double lat;
            double lng;
            int pos = xml.indexOf("<lat>");
            if(pos!=-1){
                int end = xml.indexOf("</lat>", pos);
                if(end!=-1){
                    lat = getDouble(xml.substring(pos+"<lat>".length(), end));
                    if(lat>0){
                        pos = xml.indexOf("<lng>", end);
                        if(pos!=-1){
                            end = xml.indexOf("</lng>", pos);
                            if(end!=-1){
                                lng = getDouble(xml.substring(pos+"<lng>".length(), end));
                                if(lng>0){
                                    return new double[]{lat, lng}; 
                                }
                            }
                        }
                    }
                }
            }
            
        }
        catch(Exception e){
            log.log(Level.WARNING, "getGeoCode", e);
        }
        finally{
            // 入力ストリームを閉じます
            if(in!=null){
                try {
                    in.close();
                } catch (IOException e) {}
            }
        }
        return null;
    }
    
    /***
     * 住所取得
     * 
     * @param lat
     * @param lng
     * @return
     */
    public static String getAddress(double lat, double lng){
        String ret = getAddressYahoo(lat, lng);
        return ret;
    }
    
    public static String getAddressYahoo(double lat, double lng){
        //http://reverse.search.olp.yahooapis.jp/OpenLocalPlatform/V1/reverseGeoCoder?lat=35.68381981&lon=139.77456498&appid=<あなたのアプリケーションID>
        StringBuilder url = new StringBuilder();
        url.append("http://reverse.search.olp.yahooapis.jp/OpenLocalPlatform/V1/reverseGeoCoder?");
        url.append("lat=").append(lat);
        url.append("&lon=").append(lng);
        url.append("&output=json");
        url.append("&appid=").append(Consts.YAHOO_ID);
        
        try {
            String json = getResponse(url.toString(), null);
            
            JSONObject jsonobj = new JSONObject(json);
            JSONArray features = jsonobj.getJSONArray("Feature");
            if(features!=null && features.length()>0){
                JSONObject feature = features.getJSONObject(0);
                JSONObject property = feature.getJSONObject("Property");
                return property.getString("Address");
            }
        } catch (Exception e) {
            log.log(Level.WARNING, "getAddressByYahoo", e);
        }
        return null;
    }
    
    public static String getAddressFinds(double lat, double lng){
        //finds 独立法人
        StringBuilder str = new StringBuilder();
        str.append("http://www.finds.jp/ws/rgeocode.php?json&lat=");
        str.append(lat).append("&lon=").append(lng);
        
        BufferedReader in = null;
        try{
            // URLクラスのインスタンスを生成
            URL url = new URL(str.toString());
            
            // 接続します
            URLConnection con = url.openConnection();
            con.setRequestProperty("Referer", "http://takidasibot.appspot.com/");

            // 入力ストリームを取得
            in = new BufferedReader(
                  new InputStreamReader(
                  con.getInputStream(),"UTF-8"));
    
            // 一行ずつ読み込みます
            StringBuffer json= new StringBuffer();
            String line = null;
            while ((line = in.readLine()) != null) {
              // 表示します
                json.append(line);
            }
            JSONObject jsonobj = new JSONObject(json.toString());
            if(jsonobj.has("result")){
                JSONObject result = jsonobj.getJSONObject("result");
                StringBuilder addr = new StringBuilder();
                if(result!=null){
                    
                    JSONObject prefecture = result.getJSONObject("prefecture");
                    if(prefecture!=null){
                        addr.append(prefecture.get("pname"));
                    }
                    JSONObject municipality = result.getJSONObject("municipality");
                    if(municipality!=null){
                        addr.append(municipality.get("mname"));
                    }
                    try{
                        JSONArray local = result.getJSONArray("local");
                        if(local!=null){
                            for(int i=0; i<local.length(); i++){
                                JSONObject j = local.getJSONObject(i);
                                addr.append(j.get("section"));
                            }
                        }
                    }
                    catch(Exception e){}
                }
                return addr.toString();
            }
        }
        catch(Exception e){
            log.log(Level.WARNING, "getAddressByFinds", e);
        }
        finally{
            // 入力ストリームを閉じます
            if(in!=null){
                try {
                    in.close();
                } catch (IOException e) {}
            }
        }
        return null;
    }
    
    public static void addDescription(StringBuilder source, String s, int fixsize){
        boolean flg = false;
        StringBuilder buf = new StringBuilder();
        for(int i=0; i<s.length(); i++){
            char c = s.charAt(i);
            if(c == '<'){
                flg = true;
            }
            else if( c == '>'){
                flg = false;
                if((source.length()+buf.length()+1)<fixsize){
                    source.append(buf.toString());
                }
                buf = new StringBuilder();
            }
            else if(!flg){
                buf.append(c);
            }
        }
        if((source.length()+buf.length()+1)<fixsize){
            source.append(buf.toString());
        }
    }
}
